"""
"The contents of this file are subject to the Mozilla Public License
Version 1.1 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/

Software distributed under the License is distributed on an "AS IS"
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
License for the specific language governing rights and limitations
under the License.

The Original Code is rpg-textengine (http://code.google.com/p/rpg-textengine/).

The Initial Developer of the Original Code is Devin Jeanpierre (jeanpierreda@gmail.com).

Contributor(s): 
(none)
."
"""
#these are the classes
def nouse(): print "You cannot use this item!"

class Battler:   
    #A dictionary of statistics must be given to provide the statistics for the battler 
    def __init__(self, statsdict):
        """This is called at the beginning to loead statistics from the Dictionary
        of the enemy stats"""
        import copy
        #NOTE: Always use list() and copy.deepcopy() for copying those lists! Because lists are mutable!
        self.Name = statsdict["Name"]
        self.HP = list(statsdict["HP"])
        self.TP = list(statsdict["TP"])
        self.Defense = statsdict["Defense"]
        self.BMelee = statsdict["BMelee"]
        self.BRanged = statsdict["BRanged"]
        self.Equipped = list(statsdict["Equipped"])
        self.Equipment = copy.copy((statsdict["Equipment"]))
        self.spec = list(statsdict["spec"])
        self.XP = list(statsdict["XP"])
        self.Bio = statsdict["Bio"]
        self.Effects = list(statsdict["Effects"])
    
    def ATK(self, enemy):
        """This deals attack damage to the enemy"""
        import random
        
        total = self.BMelee + self.Equipment[self.Equipped[0]].power# + miscmod
        dierolls = []
        while total != 0:
            dierolls.append(random.randint(1,10))
            total = total-1
            
        result = 0
        for roll in dierolls:
            if roll>=6:
                result=result+1
        #The following line should get the value of which item in the XP list to add XP to.
        XPType = self.Equipment[self.Equipped[0]].type
        self.EXP(result, XPType, enemy)
        #enemy.HP = enemy.HP - Core.Battle.DEF(result, enemy.Defense)# (result + miscplus)
        enemy.DEF(result)   
        return result     
    def equip(self, Weaponname):
        """Adds a weapon FROM INVENTORY to the equipped weapon slot."""
        if Weaponname in self.Equipment:
            self.Equipped[0] = Weaponname
        else:
            print "That weapon is not present in the inventory"
    def unequip(self, Weaponname):
        """Removes the weapon from the battler's hand, leaving fists"""
        self.equip("Fists")
    def take(self, item):
        """Add an item to the inventory"""
        self.Equipment.append(item)
    def drop(self, weapon):
        """Removes the weapon from the inventory"""
        del self.Equipment[weapon]
        if self.Equipped[0] == weapon: 
            self.unequip(weapon)
    def DEF(self, attackvalue):
        """Calculate damage, and remove health from this character 
        (This function is used by the enemy, they call YOU.DEF() to deal damage to YOU)"""
        result = attackvalue - self.Defense
        if result < 0: result = 0
        self.HP[0] = self.HP[0] - result
    def retDEF(self, attackvalue):
        """Return how much damage the attack would do. This is mostly to display damage amounts.
        
        NOTE: This was made a while ago, and I have to check, but I suspect
        that it can be completely unified with DEF(), and is utterly useless
        (DEF() could have a return statement)"""
        result = attackvalue - self.Defense
        if result < 0: result = 0
        return result
        
    def EXP(self, attackvalue, XPType, enemy):
        """Calculate and Add experience points to this character"""
        self.XP[XPType] = (attackvalue*enemy.Defense) + self.XP[XPType]
        
    
class Player(Battler):
    #TODO: Expand upon Battler to make a full player class, with skills and so on
    def __init__(self, statsdict):
        Battler.__init__(self, statsdict)
        
class NPC(Player):
    #TODO: Expand upon Battler to make a full NPC class, with functions for talking, selling, trading, etcetera
    def __init__(self, statsdict, talkfunction, tradefunction):
        self.talk = talkfunction
        self.trade = tradefunction
        Player.__init__(self, statsdict)
    
    

class Item:
    def __init__(self, statsdict, use=nouse):
        self.type = statsdict[0]
        self.name = statsdict[1]
    #Other uses?
    #I think that this would be a base class, which can be used for simple items.
    #Like potions.
    #And food.
    #But thats about it.
    
class Weapon(Item):
    def __init__(self, statsdict):
        self.power = statsdict[1][0]
        Item.__init__(self, [statsdict[1][1],statsdict[0]])
        

class Game:
    pass
    #Is this a good idea? I don't know. But it seems to be neccesary to be the top parent.
    #We'll se. I may end up making this a class anyway, for storing global variables and whatnot.
    #Actually, could subclass the IO class and make it a good way to access the user interface

class Map:
    def __init__(self, name="The Dungeon", parent=None):
        self.Name = name
        self.parent = parent
        self.children = []
        try:
            parent.loadmap(self)
        except AttributeError:
            self.parent = self
    
    def enter(self, player):
        """Like... get inside. By default you get into children[0], the first map loaded"""
        self.children[0].enter(player)
    
    def loadmap(self, map):
        """A 'map' can be anything from another Map to a Room. Neat, eh?
        the first one loaded is the default 'map' for the map."""
        self.children.append(map)
    
    
class Room:
    def __init__(self, parent, entities = [], items = [], name="A Room", description = "" , left=None, right=None, forward=None, backward=None):
        #self.forward=forward
        #self.backward=backward
        #self.left=left
        #self.right=right
        self.name = name
        self.directions = {"left":left, "right":right, "forward":forward, "backward":backward}
        self.entities=entities
        self.parent = parent
        parent.loadmap(self)
        self.description = description
        self.items = []
        self.next = None

    def link(self, thisportal, joinedroom, joinedportal):
        """Thisportal is, for instance, "left". or "right".
        The door for left or right in the dict (or whatever else you chose)
        is replaced with a link to the joined room, and their joinedportal leads to here.
        Easy..sure..."""
        self.directions[thisportal] = joinedroom
        joined.directions[joinedportal] = self
        
    
    def enter(self, player):
        """This sets up the room before it's activated.
        Then it activates it."""
        self.player = player
        self.activate()
        
        
    
    def move(self, command):
        """This sets the various directions that can be moved. the move() method can easily be replaced
        with a more suitable set.
        """
        if "left" in command or "west" in command:
            self.next = self.directions["left"]
        elif "right" in command or "east" in command:
            self.next = self.directions["right"]
        elif "forward" in command or "north" in command:
            self.next = self.directions["forward"]
        elif "back" in command or "south" in command:
            self.next = self.directions["backward"]
        else:
            self.next = self.directions[command]
        print "You have entered %s." % self.next.name
    
    def look(self,command):
        """This is the method for if somebody looks around. It prints the rooms description, if the person is looking around.
        This method needs to be changed to support looking at objects inside the room.
        """
        if "room" or "around" in command:
            print self.description
            return
        else:
            for item in items:
                if command.lower() == item.name.lower():
                    print item.description
                    return
            #If it wasn't an item
            for entity in entities:
                pass
            
        #If all else fails...
        print "Invalid secondary command"
    
    def take(self, command):
        """This takes an item from the room"""
        for item in self.items:
            if item in command: self.player.take(item)
    
    def talk(self, person):
        """This initiates a conversation with the person specified."""
        for guy in self.entities:
            if guy.Name in person:
                guy.talk()
                return
    
    def trade(self, person):
        """This initiates a trading session with the person specified.
        
        Such a session may be a person to person trade, or a shopping session, or whatever."""
        for guy in self.entities:
            if guy.Name in person:
                guy.trade()
                return
    
    CommDict = {"look":look, "move":move, "take":take, "talk":talk, "trade":trade}    
    
    def SplitComm(self, Input):
        """This splits a command into base and subcommand"""
        return Input[0:Input.index(' ')], (Input[Input.index(' '): -1]+Input[-1]).strip(' ')
    
    def activate(self):
        """This starts up the room and stuff. This has a reasonable default, 
        but it has been separated from enter() so that you can customize it any way you want
        It's pretty nice how it is though."""
        self.next = None
        print self.description
        print "What will you do?"
        Input = ""
        while self.next == None:
            Input = raw_input("Action::")
            Command = self.SplitComm(Input)
            try:
                self.CommDict[Command[0]](self, Command[1])
            except KeyError:
                print "Command '%s' is not a valid command in this room." % Command[0]
        self.next.enter(self.player)
        
    
    

